package com.gitee.wsl.concurrent

import com.gitee.wsl.logger.Logger
import java.util.concurrent.*
import kotlin.math.max


/**
 * common thread executor.
 *
 * @author 释慧利
 */
object ThreadExecutor {

    // fixme to user custom
    private val EXECUTOR: ExecutorService = ThreadPoolExecutor(
        cpus(), max(200, cpus() * 5),
        60L, TimeUnit.SECONDS,
        SynchronousQueue(),
        KleinThreadFactory.create("common-thread", true)
    )

    private fun cpus(): Int {
        return Runtime.getRuntime().availableProcessors()
    }

    /**
     * submit task to thread pool.
     *
     * @param task runnable
     */
    fun execute(task: Runnable) {
        EXECUTOR.execute(task)
    }

    /**
     * submit task to thread pool.
     *
     * @param task runnable
     * @param <T>  future result type
     * @return future
    </T> */
    fun <T> submit(task: Callable<T>): java.util.concurrent.Future<T> {
        return EXECUTOR.submit(task)
    }

    /**
     * The following method shuts down an `ExecutorService` in two
     * phases, first by calling `shutdown` to reject incoming tasks,
     * and then calling `shutdownNow`, if necessary, to cancel any
     * lingering tasks.
     *
     * @param pool          need close pool
     * @param timeoutMillis close timeout
     * @return is closed
     */
    /**
     * graceful shutdown.
     *
     * @param pool need close pool
     * @return is closed
     * @see .shutdownAndAwaitTermination
     */
    @JvmOverloads
    fun shutdownAndAwaitTermination(pool: ExecutorService?, timeoutMillis: Long = 1000): Boolean {
        if (pool == null) {
            return true
        }
        // disable new tasks from being submitted
        pool.shutdown()
        val unit = TimeUnit.MILLISECONDS
        val phaseOne = timeoutMillis / 5
        try {
            // wait a while for existing tasks to terminate
            if (pool.awaitTermination(phaseOne, unit)) {
                return true
            }
            pool.shutdownNow()
            // wait a while for tasks to respond to being cancelled
            if (pool.awaitTermination(timeoutMillis - phaseOne, unit)) {
                return true
            }
            Logger.w("Fail to shutdown pool: $pool.")
        } catch (e: InterruptedException) {
            // (Re-)cancel if current thread also interrupted
            pool.shutdownNow()
            // preserve interrupt status
            Thread.currentThread().interrupt()
        }
        return false
    }
}
